package com.niodata.dp.expression.function.array;

import com.googlecode.aviator.runtime.function.AbstractFunction;
import com.googlecode.aviator.runtime.function.FunctionUtils;
import com.googlecode.aviator.runtime.type.AviatorBoolean;
import com.googlecode.aviator.runtime.type.AviatorObject;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;

public class ArraySortFunction extends AbstractFunction {

  @Override
  public String getName() {
    return "array.sort";
  }

  public AviatorObject call(Map<String, Object> env, AviatorObject array) {
    return this.call(env, array, AviatorBoolean.TRUE);
  }

  /**
   * array or list sort.
   *
   * @param env env
   * @param array array
   * @param asc asc or desc(true/false)
   * @return sorted data
   */
  public AviatorObject call(Map<String, Object> env, AviatorObject array, AviatorObject asc) {
    Object v = array.getValue(env);
    boolean ascBool = ((AviatorBoolean) asc).booleanValue(env);
    if (List.class.isAssignableFrom(v.getClass())) {
      List<Comparable> list = (List) v;
      List<Comparable> result = new ArrayList<>(list);
      Collections.sort(result, new Comparator<Comparable>() {
        @Override
        public int compare(Comparable o1, Comparable o2) {
          return ascBool ? o1.compareTo(o2) : o2.compareTo(o1);
        }
      });
      return FunctionUtils.wrapReturn(result);
    } else if (v.getClass().isArray()) {
      int len = Array.getLength(v);
      Comparable[] varray = new Comparable[len];
      for (int i = 0; i < len; i++) {
        varray[i] = (Comparable) Array.get(v, i);
      }
      Arrays.sort(varray, new Comparator<Comparable>() {
        @Override
        public int compare(Comparable o1, Comparable o2) {
          return ascBool ? o1.compareTo(o2) : o2.compareTo(o1);
        }
      });
      return FunctionUtils.wrapReturn(varray);
    }
    return null;
  }
}
